﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using System.Windows.Media.Animation;
using System.Threading;

using Bohdan.Arch.Messaging;
using Bohdan.Arch.Messaging.Special;
using Bohdan.Arch.Messaging.Actors;
using Microsoft.Win32;
using System.Diagnostics;

namespace WPF_Testing_Application
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class wndMain : Window
    {
        App app = (App)App.Current;

        public wndMain()
        {
            InitializeComponent();
        }

        private void btOpen_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog dlg = new OpenFileDialog();
            bool? res = dlg.ShowDialog(this);
            if (res.HasValue && res.Value)
            {
                tbFilename.Text = dlg.FileName;
            }
        }

        List<string> lLog = new List<string>();

        public void Log(string msg)
        {
            lLog.Insert(0, DateTime.Now + ": " + msg);
            if (lLog.Count > 4)
                lLog.RemoveAt(4);
            lReport.Content = string.Join(Environment.NewLine, lLog.ToArray());
        }

        private void btProcess_Click(object sender, RoutedEventArgs e)
        {
            if (!_ClosingStarted)
            {
                IOMessage msg = new IOMessage() { Filename = tbFilename.Text };
                app.MainBus.PostMessageAsync(
                    new Bohdan.Arch.Messaging.Special.TimeCheckedMessage(
                        msg,
                        TimeSpan.FromMilliseconds(400),
                        new UIShowLongMessage(),
                        new UIHideLongMessage()
                        )
                );
            }
            else
                MessageBox.Show("We are closing... Sorry");
        }

        UIWorker worker;
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            Thread.CurrentThread.Priority = ThreadPriority.Highest;

            // ui worker
            worker = new UIWorker(this);
            app.MainBus.RegisterSubscriber(worker);

            // io worker
            app.MainBus.RegisterSubscriber(new IOWorker());

            // time manager
            app.MainBus.RegisterSubscriber(new Bohdan.Arch.Messaging.Special.TimeMeasurerSubscriber());
        }

        public void IntentionalClose()
        {
            _CanClose = true;
            this.Close();
        }

        bool _CanClose = false;
        bool _ClosingStarted = false;
        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (_CanClose)
            {
                app.Shutdown();
                return;
            }
            if (_ClosingStarted)
            {
                e.Cancel = true;
                return;
            }
            if (!_CanClose)
            {
                app.MainBus.PostShuttingDownMessageAsync(new UIExitMessage());
                _ClosingStarted = true;
                e.Cancel = true;
            }
        }

        int _LongRequests = 0;
        public void BeginReportLong()
        {
            if (Interlocked.Increment(ref _LongRequests) == 1)
            {
                Storyboard sbShow = (Storyboard)Resources["waitShow"];
                sbShow.Begin();
            }
        }

        public void EndReportLong()
        {
            int res = Interlocked.Decrement(ref _LongRequests);
            if (res == 0)
            {
                Storyboard sbHide = (Storyboard)Resources["waitHide"];
                sbHide.Begin();
            }
            else if (res < 0)
                Interlocked.Increment(ref _LongRequests);
        }

        int counter = 1;
        CancellableWaitMessage cwm = null;

        private void btSetWait_Click(object sender, RoutedEventArgs e)
        {
            string c = counter++.ToString();

            btSetWait.IsEnabled = false;

            app.MainBus.PostMessageAsync(new SequentialMessage(
                new UIMessage(c + ": started."),
                new UICustomDeletage(delegate() { btAbortWait.IsEnabled = true; }),
                
                cwm = new CancellableWaitMessage(TimeSpan.FromSeconds(3))
                {
                    OnCancelMessage = new UIMessage(c + ": cancelled"),
                    DirectMessage = new SequentialMessage(
                        new UIMessage(c + ": being executed."),
                        new WaitMessage(TimeSpan.FromMilliseconds(600)),
                        new UIMessage(c + ": done execution.")
                    )
                },
                
                new UIMessage(c + ": completed."),
                new UICustomDeletage(delegate() { btAbortWait.IsEnabled = false; btSetWait.IsEnabled = true; cwm = null; })
            ));
        }

        private void btAbortWait_Click(object sender, RoutedEventArgs e)
        {
            if (cwm != null)
                Trace.TraceInformation("{0}", cwm.TryCancel());
        }

        List<PulsarActor> _pulsars = new List<PulsarActor>();

        private void btPulse_Click(object sender, RoutedEventArgs e)
        {
            Random rnd = new Random();

            // app.MainBus
            PulsarActor pa = new PulsarActor();
            pa.Bus = app.MainBus;
            pa.Interval = TimeSpan.FromSeconds(1 + rnd.NextDouble());
            pa.Action = () => app.MainBus.PostMessageAsync(new UIMessage("pulsing " + rnd.NextDouble().ToString()));
            //pa.PulsingMessage = new UIMessage("pulsing " + rnd.NextDouble().ToString());

            _pulsars.Add(pa);
            pa.Start();
        }

        private void btStopLastOne_Click(object sender, RoutedEventArgs e)
        {
            if (_pulsars.Count > 0)
            {
                PulsarActor pa = _pulsars[_pulsars.Count - 1];
                _pulsars.RemoveAt(_pulsars.Count - 1);

                pa.Stop();
            }
            else
                Log("no more pulsars");
        }

    }
}
